package com.nana.framework.net
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	import flash.utils.Timer;
	
	public class FSocket extends Socket
	{
		private var _host:String;
		private var _port:int;
		private var _portList:Array;
		private var _portIndex:int = 0;
		private var _connected:Boolean = false;
		private var _receive:Boolean = false;
		private var timer:Timer;
		private var readHead:Boolean = false;
		private var cLength:int = 0;
		private var cCmd:int = 0;
		private var cRes:int = 0;
		private var cData:ByteArray;
		private var _connectStatus:int = 0;
		private var loginData:ByteArray;
		private var _pause:Boolean = false;
		private var dataList:Array;
		
		public function FSocket(host:String=null,port:int=0){
			super(host,port);
			this.dataList = [];
			this.endian = Endian.BIG_ENDIAN;
			this.configureListeners();
		}
		
		private function configureListeners():void{
			addEventListener(Event.CONNECT, this.onConnect);
			addEventListener(ProgressEvent.SOCKET_DATA, this.onSocketData);
			addEventListener(Event.CLOSE, this.onClose);
			addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onSecurity);
			addEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler);
		}
		
		public function reConnect():void{
			if (this.pause){
				return;
			}
			if ((this.connected == false) && (this._connectStatus == 0)){
				this._connectStatus = 1;
				this.__connect(this._host, this._port);
			}
		}
		
		public function connectMulti(host:String, ports:String):void{
			this._connectStatus = 1;
			this._host = host;
			this._portList = ports.split("|");
			this._port = this._portList[this._portIndex];
			this.__connect(host, this._port);
		}
		
		private function __connect(host:String, port:int):void{
			trace("socket 连接__host...................................", host, port);
			var event:SocketEvent = new SocketEvent(SocketEvent.TRACE_EVENT);
			event.traceValue = "host:" + host + " port:" + port + " time:" + getTimer();
			dispatchEvent(event);
			super.connect(host, port);
			if (this.timer != null){
				this.timer.removeEventListener(TimerEvent.TIMER, this.onTimer);
			}
			this.timer = new Timer(6000, 1);
			this.timer.addEventListener(TimerEvent.TIMER, this.onTimer);
			this.timer.start();
		}
		
		private function onTimer(timerEvent:TimerEvent):void{
			var socketEvent:SocketEvent = new SocketEvent(SocketEvent.TRACE_EVENT);
			socketEvent.traceValue = ("timeout:" + getTimer());
			dispatchEvent(socketEvent);
			if (this._receive == false){
				this.retrySocket();
			}
			(timerEvent.currentTarget as Timer).removeEventListener(TimerEvent.TIMER, this.onTimer);
		}
		
		private function onConnect(event:Event):void{
			var socketEvent:SocketEvent = new SocketEvent(SocketEvent.TRACE_EVENT);
			socketEvent.traceValue = ("onConnect:" + getTimer());
			dispatchEvent(socketEvent);
			this._connectStatus = 2;
			if (this.loginData != null){
				this.writeBytes(this.loginData);
				this.flush();
			}
			this.sendData();
			this._connected = true;
		}
		
		private function onClose(event:Event):void{
			var _local2:SocketEvent = new SocketEvent(SocketEvent.TRACE_EVENT);
			_local2.traceValue = ("onClose:" + getTimer());
			dispatchEvent(_local2);
			if (this.retrySocket() == false){
				dispatchEvent(new SocketEvent(SocketEvent.SOCKET_CLOSE));
				this._connectStatus = 0;
			}
		}
		
		private function onSecurity(event:SecurityErrorEvent):void{
			var socketEvent:SocketEvent = new SocketEvent(SocketEvent.TRACE_EVENT);
			socketEvent.traceValue = ("onSecurity:" + getTimer());
			dispatchEvent(socketEvent);
			if (this.retrySocket() == false){
				this._connectStatus = 0;
			}
		}
		
		private function ioErrorHandler(event:IOErrorEvent):void{
			var _local2:SocketEvent = new SocketEvent(SocketEvent.TRACE_EVENT);
			_local2.traceValue = ("ioError:" + getTimer());
			dispatchEvent(_local2);
			this.retrySocket();
		}
		
		private function retrySocket():Boolean{
			if ((this._portIndex >= (this._portList.length - 1)) || (this._receive == true)){
				return false;
			}
			this._portIndex = (this._portIndex + 1);
			this._port = this._portList[this._portIndex];
			this.__connect(this._host, this._port);
			return true;
		}
		
		private function onSocketData(event:ProgressEvent):void{
			var socketEvent:SocketEvent = new SocketEvent(SocketEvent.TRACE_EVENT);
			socketEvent.traceValue = "onData";
			dispatchEvent(socketEvent);
			this._receive = true;
			while (this.bytesAvailable > 0) {
				if (!this.readHead){
					if (this.bytesAvailable >= 8){
						this.cLength = this.readUnsignedInt();
						this.cCmd = this.readUnsignedShort();
						this.cRes = this.readUnsignedShort();
						this.readHead = true;
					} else {
						break;
					}
				}
				if (this.readHead){
					if (this.bytesAvailable >= this.cLength){
						if (this.cLength > 0){
							this.cData = new ByteArray();
							this.readBytes(this.cData, 0, this.cLength);
						} else {
							this.cData = null;
						}
						var sevt:SocketEvent = new SocketEvent(SocketEvent.DATA_COMP);
						sevt.cmd = this.cCmd;
						sevt.data = this.cData;
						sevt.res = this.cRes;
						dispatchEvent(sevt);
						this.readHead = false;
					} else {
						break;
					}
				}
			}
		}
		
		public function send(type:int, bytes:ByteArray, roomId:int=0, _arg4:String=""):void{
			var socketEvent:SocketEvent = new SocketEvent(SocketEvent.TRACE_EVENT);
			socketEvent.traceValue = "send";
			dispatchEvent(socketEvent);
			var length:uint = bytes.length;
			var byteData:ByteArray = new ByteArray();
			byteData.endian = Endian.LITTLE_ENDIAN;
			byteData.writeUnsignedInt(length);
			byteData.writeShort(type);
			byteData.writeShort(roomId);
			byteData.writeBytes(bytes);
			if (this.loginData == null){
				this.loginData = byteData;
				if (this._connected){
					this.writeBytes(this.loginData);
					this.flush();
				}
			} else {
				this.dataList.push(byteData);
				this.sendData();
			}
		}
		
		private function sendData():void{
			if (this.pause){
				return;
			}
			if (this.connected){
				while (this.dataList.length > 0) {
					var bytes:ByteArray = (this.dataList.shift() as ByteArray);
					this.writeBytes(bytes);
					this.flush();
				}
			} else {
				if (this._connectStatus == 0){
					this.__connect(this._host, this._port);
				}
			}
		}

		public function get receive():Boolean
		{
			return _receive;
		}

		public function get pause():Boolean
		{
			return _pause;
		}

		public function set pause(value:Boolean):void
		{
			if (value && this.connected){
				this.close();
			}
			_pause = value;
		}

	}
}